#pragma once



namespace chen
{
	template <class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}

		auto_ptr(const auto_ptr& s)
			:_ptr(s.ptr)
		{
			s._ptr = nullptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		//s1 = s2
		auto_ptr<T>& operator=(const auto_ptr& s)
		{
			if (_ptr)
			{
				delete _ptr;
				_ptr = nullptr;
			}

			_ptr = s._ptr;
			s._ptr = nullptr;
		}



		~auto_ptr()
		{
			if (_ptr)
				delete _ptr;
		}

	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}

		~unique_ptr()
		{
			if(_ptr)
				delete _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;
		unique_ptr(const unique_ptr<T>&) = delete;
	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,_count(new int(1))
		{}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return *_ptr;
		}

		//s1(s2)
		shared_ptr(const shared_ptr<T>& s)
		{
			_ptr = s._ptr;
			_count = s._count;
			++(*_count);
		}

		//s1 = s2;
		shared_ptr<T>&  operator=(const shared_ptr<T>& s)
		{
			if (_ptr == s._ptr)
			{
				return *this;
			}

			if (--(*_count) == 0)
			{
				delete _ptr;
				delete _count;
			}

			_ptr = s._ptr;
			_count = s._count;
			++(*_count);
			return *this;
		}

		~shared_ptr()
		{
			if (--(*_count) == 0)
			{
				delete _ptr;
				delete _count;
			}
		}

	private:
		T* _ptr;
		int* _count;
	};

}